#pragma once
#include "../common/message.hpp"
#include "../common/net.hpp"
#include <future> //用于实现异步回调
namespace rpc
{

    namespace client
    {

        class Requestor
        {
        public:
            // 回调
            using ptr = std::shared_ptr<Requestor>;
            // 函数回调
            using CallBack = std::function<void(const BaseMessage::ptr &)>;
            // 异步回调
            using Asyncptr = std::future<BaseMessage::ptr>;
            // 描述内部类
            struct RequestDescribe
            {
                using ptr = std::shared_ptr<RequestDescribe>;
                // 请求id
                std::string rid;
                // 响应类型
                RPC_REQ type;
                // 异步回调
                std::promise<BaseMessage::ptr> responseAsync;
                // 函数回调
                CallBack responseCallback;
            };

            void onResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) // 为dispactor模块进行注册服务使用
            {
                // 先找到响应描述
                auto it = selectDescribe(msg->getId());
                if (it.get() == nullptr)
                {
                    errlog("已收到请求：%s,未找到方法", msg->getId().c_str());
                    return;
                }

                // 查看请求类型
                // 如果是异步请求，那就设置value
                if (it->type == RPC_REQ::ASYNC)
                {
                    it->responseAsync.set_value(msg);
                } // 如果是函数回调请求，那就调用callBack方法
                else if (it->type == RPC_REQ::CBACK)
                {
                    if (it->responseCallback)
                        it->responseCallback(msg);
                }
                else
                {
                    errlog("未知类型");
                    return;
                }

                removeDescribe(msg->getId()); // 处理完请求就删除掉，防止内存泄漏
            }

            // 异步回调响应
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg, Asyncptr &response)
            {
                // 构造一个describe对象
                delog("send开始构造describe对象");
                auto desc = newDescribe(msg, RPC_REQ::ASYNC);
                delog("send开始构造describe对象结束");
                // 判断是否构造成功
                if (desc.get() == nullptr)
                {
                    errlog("异步调用构造失败");
                    return false;
                }

                // 异步对象获取结果
                if (conn)
                {
                    delog("异步结果获取");
                    conn->send(msg);
                }
                response = desc->responseAsync.get_future();
                return true;
            }
            // 同步响应
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg, BaseMessage::ptr &response)
            {
                // 构建异步
                Asyncptr asyn_future;
                // 调用异步send
                delog("send开始调用send回调");
                bool ret = send(conn, msg, asyn_future);
                delog("send回调结束");
                if (ret == false)
                {
                    return false;
                }
                // 获取异步值
                delog("send开始获取异步值");
                response = asyn_future.get();
                 delog("send获取异步值成功");
                return true;
            }

            // 函数回调响应
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg, CallBack &response)
            {
                // 构建回调描述
                auto desc = newDescribe(msg, RPC_REQ::CBACK, response);
                // 判断是否构造成功
                if (desc.get() == nullptr)
                {
                    errlog("同步调用构造失败");
                    return false;
                }
                conn->send(msg);
                return true;
            }

            // 增删查
            RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RPC_REQ type,
                                             const CallBack &cb = CallBack())
            {
                std::unique_lock<std::mutex> lock(_mutex);
                delog("开始构造describe对象");
                // 构造一个对象指针
                RequestDescribe::ptr desc = std::make_shared<RequestDescribe>();
                desc->rid = req->getId();
                desc->type = type;
                // 如果是回调类型还要设置回调
                if (desc->type == RPC_REQ::CBACK)
                {
                    if (cb)
                        desc->responseCallback = cb;
                }
                _requstDescribe.insert(std::make_pair(desc->rid, desc));
                delog("send开始构造describe对象结束， _requstDescribe插入describe对象");
                return desc;
            }

            RequestDescribe::ptr selectDescribe(const std::string &id)
            {
                auto it = _requstDescribe.find(id);
                if (it == _requstDescribe.end())
                {
                    errlog("未找到服务");
                    return RequestDescribe::ptr();
                }
                return it->second;
            }

            void removeDescribe(const std::string id)
            {
                auto it = _requstDescribe.find(id);
                _requstDescribe.erase(it);
            }

        private:
            std::mutex _mutex;
            // id与描述进行映射
            std::unordered_map<std::string, RequestDescribe::ptr> _requstDescribe;
        };
    }
}